/**
 * Copyright (c) 2018 人人开源 All rights reserved.
 * <p>
 * https://www.renren.io
 * <p>
 * 版权所有，侵权必究！
 */

package com.base.commons.tools.utils;


import com.opencsv.CSVWriter;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import com.base.commons.tools.exception.BaseOfException;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * csv工具类
 *
 * @author carl
 * @since 1.0.0
 *
 */
public class CsvOpenUtils {

    /**
     * csv导出
     *
     * @param response      response
     * @param fileName      文件名
     * @param list          数据List
     *
     */
    public static <T> void exportCsv(HttpServletResponse response, String fileName, List<T> list
            , Class<?> targetClass) throws IOException {

        if (StringUtils.isBlank(fileName)) {
            //当前日期
            fileName = DateUtils.format(new Date());
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".csv");
        OutputStream outputStream = response.getOutputStream();

        try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
             BufferedWriter writer = new BufferedWriter(outputStreamWriter)
        ) {
            writer.write("\ufeff");
            StatefulBeanToCsv<T> beanToCsv = gettStatefulBeanToCsv((Class<? extends T>) targetClass, writer,true);
            try {

                beanToCsv.write(list);
            } catch (CsvDataTypeMismatchException e) {
                e.printStackTrace();
            } catch (CsvRequiredFieldEmptyException e) {
                e.printStackTrace();
            }

        }

    }

    private static <T> StatefulBeanToCsv<T> gettStatefulBeanToCsv(Class<? extends T> targetClass, BufferedWriter writer,boolean isNeedHeader) {
        CustomMappingStrategy<T> strategy = new CustomMappingStrategy<>(isNeedHeader);
        strategy.setType(targetClass);
        return (StatefulBeanToCsv<T>) new StatefulBeanToCsvBuilder(writer)
                .withQuotechar(CSVWriter.DEFAULT_ESCAPE_CHARACTER)
                .withQuotechar(CSVWriter.DEFAULT_SEPARATOR)
                .withQuotechar(CSVWriter.DEFAULT_QUOTE_CHARACTER)
                .withMappingStrategy(strategy)
                .build();
    }

    /**
     * csv导出
     *
     * @param csvPath      文件目录
     * @param fileName      文件名
     * @param list          数据List
     *
     */
    public static <T> void exportCsvPath(String csvPath, String fileName, List<T> list, Class<?> targetClass) {

        if (StringUtils.isBlank(fileName)) {
            //当前日期
            fileName = DateUtils.format(new Date());
        }
        FileOutputStream fileOutputStream = null;
        OutputStreamWriter outputStreamWriter = null;
        BufferedWriter writer = null;
        try {
            File file = new File(csvPath + File.separator + fileName + ".csv");
            boolean isWriteUtf8BomAndHeader = !file.exists();
            fileOutputStream = new FileOutputStream(csvPath + File.separator + fileName + ".csv", true);
            if (isWriteUtf8BomAndHeader) {
                fileOutputStream.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
            }
            outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
            writer = new BufferedWriter(outputStreamWriter);
            StatefulBeanToCsv<T> beanToCsv = gettStatefulBeanToCsv((Class<? extends T>) targetClass, writer,isWriteUtf8BomAndHeader);
            beanToCsv.write(list);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (outputStreamWriter != null) {
                try {
                    outputStreamWriter.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }

    }

    /**
     * csv导出，先sourceList转换成List<targetClass>，再导出
     *
     * @param csvPath      文件目录
     * @param fileName      文件名
     * @param sourceList    原数据List
     * @param targetClass   目标对象Class
     */
    public static void exportCsvToTarget(String csvPath, String fileName, List<?> sourceList,
                                         Class<?> targetClass) throws Exception {
        if (StringUtils.isBlank(csvPath)) {
            throw new BaseOfException("文件目录不能为空");
        }
        List targetList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            Object target = targetClass.newInstance();
            BeanUtils.copyProperties(source, target);
            targetList.add(target);
        }
        exportCsvPath(csvPath, fileName, targetList, targetClass);
    }

    /* */

    /**
     * 动态标题
     * csv导出，先sourceList转换成List<targetClass>，再导出
     *
     * @param csvPath      文件目录
     * @param fileName      文件名
     * @param sourceList    原数据List
     * @param targetClass   目标对象Class
     */
    public static void exportCsvToTargetDynamicHeader(String csvPath, String fileName, List<?> sourceList,
                                                      Class<?> targetClass, MultiValuedMap<String, String> tableHeader) throws Exception {
        HashSetValuedHashMap<String, String> headerMap = null;
        if (StringUtils.isBlank(csvPath)) {
            throw new BaseOfException("文件目录不能为空");
        }
        List targetList = new ArrayList<>(sourceList.size());
        for (int i = 0; i < sourceList.size(); i++) {
            Object source = sourceList.get(i);
            Object target = targetClass.newInstance();
            BeanUtils.copyProperties(source, target);
            if (tableHeader != null && i == 0) {
                org.apache.commons.beanutils.BeanUtils.setProperty(target, "feeDetail", tableHeader);
            } else {
                org.apache.commons.beanutils.BeanUtils.setProperty(target, "feeDetail", headerMap);
            }
            targetList.add(target);

        }
        exportCsvPath(csvPath, fileName, targetList, targetClass);
    }

    /**
     * csv导出，先sourceList转换成List<targetClass>，再导出
     *
     * @param response      response
     * @param fileName      文件名
     * @param sourceList    原数据List
     * @param targetClass   目标对象Class
     */
    public static void exportCsvToTarget(HttpServletResponse response, String fileName, List<?> sourceList,
                                         Class<?> targetClass) throws Exception {

        List targetList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            Object target = targetClass.newInstance();
            BeanUtils.copyProperties(source, target);
            targetList.add(target);
        }
        exportCsv(response, fileName, targetList, targetClass);
    }

//<<<<<<< HEAD
//    /**
//     * 根据bean填充已有表头
//     *
//     * @param obj
//     * @param tableHeader
//     */
//    public static void generateTableHeader(Object obj, MultiValuedMap<String, String> tableHeader) {
//        initTableHeader(obj, tableHeader, "costFeeDetail", "(成本)",false);
//        initTableHeader(obj, tableHeader, "incomeFeeDetail", "(收入)",false);
//    }
//    public static void initTableHeader(Object obj, MultiValuedMap<String, String> tableHeader, String fieldName, String alias,boolean isInitHeader) {
//        String cost_fee_detail;
//        try {
//            cost_fee_detail = org.apache.commons.beanutils.BeanUtils.getProperty(obj, fieldName);
//            if (StringUtils.isEmpty(cost_fee_detail)) {
//                return;
//            }
//            String[] costFee = cost_fee_detail.split(",");
//            for (String fee : costFee) {
//                String[] feeDetail = fee.split(":");
//                if (tableHeader.containsKey(feeDetail[1] + alias)) {
//                    tableHeader.remove(feeDetail[1] + alias);
//                }
//                if (isInitHeader) {
//                    tableHeader.put(feeDetail[1] + alias, null);
//                } else {
//                    tableHeader.put(feeDetail[1] + alias, feeDetail[2]);
//                }
//
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
//=======
}
